var template = `
<div class="runner">
    <hr/>
    <div v-if="banMsg">{{banMsg}}</div>
    <div v-if="sharedState.runTask">
        runTask
        <div v-if="runTask" class="form">
            <div v-for="key in Object.keys(showModel)">
                <div class="label"><label>{{doGetKey(key)}}:</label></div>
                <div class="input">{{doFormat(runTask,key)}}</div>
                <div style="clear:both;"></div>
            </div>
        </div>
    </div>
    <div class="no-data" v-else>没有数据</div>
</div>
`;

let Runner = {
    name: 'Runner',
    components: {},
    template,
    props: {},
    data() {
        return {
            sharedState: store.state,
            punishMs: appConfig.heartBeatPunish * 1000,
            lastTimeOutId: -1,
            timeoutMs: appConfig.heartBeatFixedDelay * 1000,
            lastSuccessTime: Date.now(),
            lastCostTime: -1,
            exit: false,
            sleepTimeMs: 10,
            runTask: null,
            nextList: [],
            nextModel: {
                // 下一个方法名
                name: '',
                // 下一个方法入参
                param: {}
            },
            // 任务栈计数
            nextCount: 0,
            // 任务栈空闲计数 空闲10次
            nextNothingCount: 0,
            runnerId: UUID(),
            config: {},
            isUserCheck: false,
            isUserOk: false,
            isProxyOk: false,
            // 任务是否正常
            isTaskOk: false,
            taskFailCount: 0,
            taskCheckUrl: '',
            sharedData: null,
            username: '',
            current: -1,
            currentId: '',
            total: -1,
            tempPost: null,
            tempPostEdges: null,
            tempPostEdgesSize: null,
            tempPostEdgesIndex: 0,
            tempPostEdgesFailCount: 0,
            tempPicImagePaths: [],
            tempPicList: [],
            ignoreGetImage: appConfig.ignoreGetImage,
            updateEdgeList: [],
            updateEdgeListIndex: -1,
            updateEdgeListSize: -1,
            schema: '任务信息',
            showModel: {
                taskName: '',
                currentId: '',
                // threadSize:'',
                // first:'',
                total: '',
                current: '',
                percentSuccess: '',
                // timeoutExecTime:'',
                // runningThread:'',
                running: '',
                paused: '',
                firstExecTime: {
                    type: 'date',
                    formatter: 'yyyy-MM-dd HH:mm:ss'
                },
                lastExecTime: {
                    type: 'date',
                    formatter: 'yyyy-MM-dd HH:mm:ss'
                },
                latestActiveTime: {
                    type: 'date',
                    formatter: 'yyyy-MM-dd HH:mm:ss'
                },
                createdTime: {
                    type: 'date',
                    formatter: 'yyyy-MM-dd HH:mm:ss'
                },
                updatedTime: {
                    type: 'date',
                    formatter: 'yyyy-MM-dd HH:mm:ss'
                },
            },
            banMsg: '',
        }

    },
    methods: {
        doGetKey(key = '') {
            let {apiDocs} = this.sharedState;
            if (apiDocs) {
                let {schemas = {}} = apiDocs.components;
                let schemaObj = schemas[this.schema];
                if (schemaObj) {
                    return schemaObj.properties && schemaObj.properties[key] && schemaObj.properties[key].description || key;
                }
            }
            return key;
        },
        doFormat(item, key) {
            if (this.showModel[key] && this.showModel[key].formatter) {
                if ('date' === this.showModel[key].type) {
                    return new Date(item[key]).fmt(this.showModel[key].formatter);
                } else {
                    return item[key];
                }
            } else if ('text' === this.showModel[key].type) {
                if (this.showModel[key].maxLength && this.showModel[key].maxLength > 0) {
                    let maxLength = this.showModel[key].maxLength;
                    if (typeof (item[key]) === 'string' && item[key].length > maxLength) {
                        return item[key].substr(0, maxLength) + '...';
                    } else {
                        return item[key];
                    }
                } else {
                    return item[key];
                }
            } else {
                return item[key];
            }
        },
        async doInit() {
            let {runTask} = this.sharedState;
            if (!runTask) {
                return;
            }
            this.runTask = runTask;
            let {firstExecTime = 0} = runTask;
            if (firstExecTime <= 0) {
                firstExecTime = Date.now();
                runTask.firstExecTime = firstExecTime;
            }
            runTask.lastExecTime = Date.now();
            let config = await this.doGetConfig();
            let total = await this.doGetTotal(runTask.total);
            this.total = total;
            runTask.total = total;
            this.config = config;
            let {isUserCheck = false} = config;
            let {sleepTaskMs} = config;
            sleepTaskMs = sleepTaskMs > 0 ? sleepTaskMs : appConfig.defaultSleepTaskMs;
            let lastTaskMs = localStorage.getItem("lastTaskMs");
            if (lastTaskMs && Date.now() - Number(lastTaskMs) < sleepTaskMs) {
                let msg = ['任务启动失败!', `上次任务过去时间不够久 ${new Date(Number(lastTaskMs)).fmt()}`];
                console.warn(...msg);
                this.$message({message: msg});
                this.doStop();
                return;
            }
            this.isUserCheck = isUserCheck;
            if (!isUserCheck) {
                this.isUserOk = true;
            }
            let {sleepTimeMs = 500} = config;
            this.sleepTimeMs = sleepTimeMs;
            this.timeoutMs = sleepTimeMs;
            this.doPushNext({name: 'update'});
            this.doStart();
        },
        async doStart() {
            let {runTask} = this.sharedState;
            if (!runTask) {
                let msg = ['任务启动异常!', 'runTask:' + typeof (runTask)];
                console.error(...msg);
                this.$message({message: msg, level: 'error'});
                this.doStop();
                return;
            }
            let {taskName = ''} = runTask;
            this.$message({message: ['任务开始', taskName]});
            let startCount = 0;
            while (!this.exit) {
                if (this.sleepTimeMs <= 1000) {
                    this.sleepTimeMs = 1000;
                }
                await this.sleep(this.sleepTimeMs);
                // ------
                // ------
                // ------ 局部函数
                let isPaused = async () => {
                    let start = Date.now();
                    while (runTask.paused && runTask.running) {
                        await this.sleep(this.sleepTimeMs);
                        let past = Date.now() - start;
                        if (past / 1000 > 30) {
                            let msg = [`任务暂停中 ${this.runnerId}`, `current=${this.current} cid=${this.currentId}`];
                            console.log(...msg);
                            this.$message({message: msg});
                            start = Date.now();
                        }
                    }
                };
                let isFinished = () => this.current + 1 === this.total;
                let isRunning = () => runTask.running && !appConfig.allStop;
                let isTaskInterval = () => 0;
                // ------
                // ------
                // ========
                // ========
                // ======== 任务执行
                // ========
                // ========
                // ========
                // ========
                if (isFinished()) {
                    localStorage.setItem("lastTaskMs", String(Date.now()));
                    this.$message();
                    this.doStop();
                    this.exit = true;
                    break;
                }
                // =====  检查用户
                if (this.isUserCheck) {
                    /*
                    检查用户登录
                     */
                }
                // ====== 获取登录信息
                await isPaused();
                try {
                    runTask.latestActiveTime = Date.now();
                    await this.doGetSharedData();
                } catch (e) {
                    let msg = ['获取登录信息失败!'];
                    this.$message({message: msg, level: 'error'});
                    console.log(...msg, e);
                    this.exit = true;
                    this.doStop();
                    continue;
                }
                // ========= 检查登录信息
                await isPaused();
                try {
                    runTask.latestActiveTime = Date.now();
                    await this.doCheckTask();
                } catch (e) {
                    let msg = ['检查任务失败!', e];
                    console.log(...msg);
                    this.$message({message: msg, level: 'error'});
                    this.exit = true;
                    this.doStop();
                    continue;
                }
                // ==========  执行任务
                if (!runTask.running) {
                    this.doStop();
                    continue;
                }
                if (runTask.paused) {
                    continue;
                }
                /*
                获取用户id
                 */
                await isPaused();
                try {
                    if (this.current < 0) {
                        runTask.latestActiveTime = Date.now();
                        await this.doGetNextId();
                    }
                } catch (e) {
                    console.log('获取用户id失败', e);
                    await this.doPunish(this.punishMs);
                    continue;
                }
                /*
                获取用户帖子
                 */
                await isPaused();
                try {
                    runTask.latestActiveTime = Date.now();
                    await this.doGetPost();
                } catch (e) {
                    console.log('获取用户帖子失败! uid=' + this.currentId, e);
                    await this.doPunish(this.punishMs);
                    continue;
                }
                /*
                获取用户帖子图片及更新
                 */
                while (this.current !== -1) {
                    await this.sleep(this.sleepTimeMs);
                    await isPaused();
                    if (!isRunning()) {
                        break;
                    }
                    try {
                        runTask.latestActiveTime = Date.now();
                        await this.doGetPic();
                    } catch (e) {
                        console.log('下载图片失败! uid=' + this.currentId, e);
                        await this.doPunish(this.punishMs);
                    }
                }
                /*
                上传未传完的用户帖子数据
                 */
                this.tempPostEdgesFailCount = 0;
                this.updateEdgeListIndex = 0;
                this.updateEdgeListSize = this.updateEdgeList.length;
                while (this.updateEdgeList.length > 0) {
                    await this.sleep(this.sleepTimeMs);
                    await isPaused();
                    if (!isRunning()) {
                        break;
                    }
                    try {
                        runTask.latestActiveTime = Date.now();
                        await this.doUpdateEdge();
                    } catch (e) {
                        console.log('上传用户帖子失败! uid=' + this.currentId, e);
                        await this.doPunish(this.punishMs);
                    }
                }

                if (!isRunning()) {
                    console.log('一次循环执行完毕', startCount++);
                    break;
                }
                this.update();
            }
            this.doStop();
            console.log('任务退出!')
        },
        async doPunish(timeMs = 0) {
            this.timeoutMs = this.timeoutMs + this.punishMs;
            await this.sleep(this.timeoutMs);
            this.timeoutMs = 0;
        },
        update() {
            let {runTask} = this.sharedState;
            if (runTask) {
                console.log('更新任务');
                this.$emit('update', runTask);
            }
        },
        doGetTotal(failNumber = 0) {
            return new Promise((resolve, reject) => {
                api.ins.count().then(res => {
                    if (res.data && res.data.code === 0) {
                        let total = res.data.data;
                        resolve(total);
                        return;
                    }
                    resolve(failNumber);
                }).catch(e => {
                    console.error("读取用户总数失败!", e);
                    resolve(failNumber);
                })
            })
        },
        doGetConfig() {
            return new Promise(((resolve, reject) => {
                api.config.getAll().then(res => {
                    if (res.data && res.data.code === 0) {
                        if (res.data.data.length > 0) {
                            let config = res.data.data[0];
                            resolve(config);
                            return;
                        }
                    }
                    resolve({});
                }).catch((e) => {
                    console.error("读取配置文件失败!", e);
                    resolve({});
                })
            }))
        },
        async sleep(sleepMs = this.sleepTimeMs) {
            return new Promise(((resolve, reject) => {
                setTimeout(() => {
                    resolve()
                }, sleepMs)
            }))
        },
        doPushNext(param = null) {
            /*
            这里可以加前后置执行器, 所有任务栈的添加都用这个方法
             */
            if (param) {
                // @Deprecated
                // this.nextList.push(param);
            }
        },
        async doNext() {
            this.nextCount++;
            let stackNext = this.doNext;
            let next = this.nextList.shift();
            let {sleepTimeMs = 100} = this;
            this.lastTimeOutId = setTimeout(() => {
                clearTimeout(this.lastTimeOutId);
                if (this.exit) {
                    console.log('任务栈退出', this.runnerId);
                    return;
                }
                if (!next) {
                    this.timeoutMs = this.punishMs;
                    this.nextNothingCount++;
                    if (this.nextNothingCount > 10) {
                        let nothingSecond = this.nextNothingCount * this.punishMs / 1000;
                        let msg = ['任务异常', '任务栈长期空闲' + nothingSecond + 's'];
                        console.log(...msg);
                        this.$message({message: msg, level: 'error'})
                    }
                    console.warn('任务栈空闲惩罚: %ss', this.timeoutMs / 1000);
                    this.doWhatToDo();
                    stackNext();
                } else {
                    let funName = next.name;
                    let param = next.param;
                    let nextCall = this[funName];
                    if (!nextCall) {
                        this.timeoutMs = this.punishMs;
                        console.warn('任务栈无效参数惩罚: %ss next: %o', this.timeoutMs / 1000, next);
                        stackNext();
                        return;
                    }
                    let promise;
                    if (typeof (param) === 'undefined') {
                        promise = nextCall();
                    } else {
                        promise = nextCall(param);
                    }
                    if (typeof (promise) === 'object' && promise instanceof Promise) {
                        promise.then(() => {
                            this.timeoutMs = this.sleepTimeMs;
                            stackNext();
                        }).catch(e => {
                            this.timeoutMs = this.timeoutMs + this.punishMs;
                            console.warn('任务栈调用异常惩罚: %ss', this.timeoutMs / 1000);
                            console.error('任务栈调用异常! funName: %s param: %o', funName, param, e);
                            e = typeof (e) === 'undefined' ? 'undefined' : e;
                            let err = e instanceof Error ? e.message : JSON.stringify(e);
                            let msg = ['任务栈调用异常!', 'funName: ' + funName, 'param: ' + JSON.stringify(param), '错误信息: ' + err];
                            this.$message({message: msg, level: 'error', duration: 5});
                            stackNext();
                        })
                    } else {
                        this.timeoutMs = this.sleepTimeMs;
                        stackNext();
                    }
                }
            }, this.timeoutMs)
        },
        doCheckLogin() {

        },
        doStop() {
            let {runTask} = this.sharedState;
            if (runTask) {
                runTask.paused = false;
                runTask.running = false;
                this.update();
                this.sharedState.runTask = null;
                this.exit = true;
                let {taskName = ''} = runTask;
                this.$message({message: ['任务结束', taskName]});
            }
        },
        doWhatToDo() {
            let {runTask} = this.sharedState;
            if (runTask) {
                if (this.nextList.length > 0) {
                    return;
                }
                if (this.isUserCheck) {
                    // 添加检查用户任务栈
                }
                if (this.isUserOk) {
                    // 添加任务下载任务栈
                    if (this.isTaskOk) {
                        if (runTask.running && !runTask.paused) {
                            let next_getNextId = {
                                name: 'doGetNextId'
                            };
                            let next_getPost = {
                                name: 'doGetPost'
                            };
                            let next_getPic = {
                                name: 'doGetPic'
                            };
                            let next_updateEdge = {
                                name: 'doUpdateEdge'
                            };
                            this.nextList.push(next_getNextId);
                            this.nextList.push(next_getPost);
                            this.nextList.push(next_getPic);
                            this.nextList.push(next_updateEdge);
                        }
                    } else {
                        // 检查任务状态
                        if (!this.sharedData) {
                            let next_getSharedData = {
                                name: 'doGetSharedData'
                            };
                            this.nextList.push(next_getSharedData);
                        }
                        let next_checkTask = {
                            name: 'doCheckTask'
                        };
                        this.nextList.push(next_checkTask);
                    }
                }
            }
        },
        async doUpdateEdge() {
            return new Promise((resolve, reject) => {
                let updateEdgeFailMax = 10;
                if (this.tempPostEdgesFailCount >= updateEdgeFailMax) {
                    this.tempPostEdgesFailCount = 0;
                    let failSize = this.updateEdgeList.length;
                    let {current: cur, currentId: cid} = this;
                    let msg = ['放弃更新帖子数据',
                        '连续' + updateEdgeFailMax + '次更新失败',
                        '放弃[' + failSize + ']条未更新数据',
                        'cur= ' + cur + ' cid= ' + cid];
                    console.log(...msg);
                    this.$message({message: msg, level: 'error'});
                    this.updateEdgeList.clear();
                    resolve();
                    return;
                }
                let edge = this.updateEdgeList.shift();
                if (!edge) {
                    resolve();
                    return;
                }
                api.post.addOrUpdate(edge).then(res => {
                    let {current, currentId: cid, tempPostEdgesIndex: index} = this;
                    if (res.data && res.data.code === 0) {
                        this.updateEdgeListIndex++;
                        let msg = ['更新帖子成功!', `${this.updateEdgeListIndex} of ${this.updateEdgeListSize}`, 'cid=' + cid, 'id=' + edge.id];
                        console.log(...msg);
                        this.$message({message: msg});
                        resolve();
                        return;
                    }
                    let msg = ['更新帖子失败!', `${this.updateEdgeListIndex} of ${this.updateEdgeListSize}`, 'cid=' + cid, 'id=' + edge.id];
                    console.log(msg, res);
                    this.$message({message: msg, level: 'error'});
                    this.tempPostEdgesFailCount++;
                    this.updateEdgeList.push(edge);
                    // 此处跳转到最外层主循环,不会进到下面行的catch
                    reject(res);
                }).catch(e => {
                    let msg = ['更新帖子失败!!', `${this.updateEdgeListIndex} of ${this.updateEdgeListSize}`, 'msg=' + e.message, 'id=' + edge.id];
                    console.log(msg, e);
                    this.$message({message: msg, level: 'error'});
                    this.tempPostEdgesFailCount++;
                    this.updateEdgeList.push(edge);
                    reject(e);
                })
            })
        },
        async doGetPic() {
            let {runTask} = this.sharedState;
            if (!runTask) {
                let msg = ['获取getPic异常!', 'runTask:' + typeof (runTask)];
                console.error(...msg);
                this.$message({message: msg, level: 'error'});
                return;
            }
            let tempPost = this.tempPost;
            if (!tempPost) {
                let msg = ['获取getPic异常!', 'tempPost:' + typeof (tempPost)];
                console.error(...msg);
                this.$message({message: msg, level: 'error'});
                return;
            }
            if (this.tempPostEdgesIndex < this.tempPostEdgesSize) {
                // a edge post
                let nextEdge = this.tempPostEdges[this.tempPostEdgesIndex].node;
                let likeCount = nextEdge['edge_media_preview_like']['count'];
                let commentCount = nextEdge['edge_media_to_comment']['count'];
                nextEdge.timingSequenceData = [
                    {
                        "likeCount": likeCount,
                        "commentCount": commentCount,
                        "currentTime": new Date()
                    }
                ];
                let image_paths = [];
                nextEdge['image_paths'] = image_paths;
                let displayUrl = nextEdge['display_url'];
                if (!displayUrl) {
                    let msg = ['没有图片', ' current: ' + this.current + ' uid: ' + this.currentId, ' pid: ' + this.currentId + ' i: ' + this.tempPostEdgesIndex];
                    console.warn(...msg);
                    this.$message({message: msg});
                    this.tempPostEdgesIndex++;
                    this.tempPostEdgesFailCount = 0;
                    return;
                }
                let failMethod = (e) => {
                    if (this.tempPostEdgesFailCount >= 3) {
                        let msg = ['图片下载失败!', '图片3次下载失败', '跳过当前图片下载 index: ' + this.tempPostEdgesIndex];
                        console.log(...msg, e);
                        this.$message({message: msg, level: 'error'});
                        this.tempPostEdgesIndex++;
                        this.tempPostEdgesFailCount = 0;
                        if (this.ignoreGetImage) {
                            this.updateEdgeList.push(nextEdge);
                        }
                        throw new Error('图片下载失败,超时');
                    }
                    this.tempPostEdgesFailCount++;
                };
                let typeName = nextEdge['__typename']
                let imageUrls = [displayUrl]
                if ('GraphSidecar' === typeName) {
                    let {edge_sidecar_to_children = {}} = nextEdge
                    let {edges = []} = edge_sidecar_to_children
                    let displayUrls = edges.map(e => e.node.display_url)
                    imageUrls.push(...displayUrls)
                    // 图片url去重
                    imageUrls = Array.from(new Set(imageUrls))
                    console.log('==== 多图片 ====', imageUrls, imageUrls.map(e => sha1(e)))
                }
                /*
                下载帖子图片;
                并且上传帖子图片
                 */
                for (let i = 0; i < imageUrls.length; i++) {
                    let imageUrl = imageUrls[i]
                    // todo 这里要拆分成单独的图片下载上传
                    try {
                        let imagePath = await this.doDownLoadPicture(imageUrl, i + 1, imageUrls.length)
                        if (imagePath) {
                            image_paths.push(imagePath)
                        } else {
                            failMethod(e)
                            return
                        }
                    } catch (e) {
                        failMethod(e)
                        return
                    }
                }
                nextEdge['image_paths'] = image_paths;
                this.tempPostEdgesIndex++;
                this.updateEdgeList.push(nextEdge);

            } else {
                // 当前 post 下载完成
                let msg = ['帖子 ' + this.currentId + '下载完成!'];
                console.log(...msg);
                this.tempPostEdges = null;
                this.tempPostEdgesIndex = 0;
                this.tempPostEdgesSize = 0;
                this.tempPostEdgesFailCount = 0;
                this.tempPicImagePaths = [];
                // 执行下一个id
                this.current = -1;
                this.tempPost = null;
                this.$message({message: msg});
            }
        },
        async doDownLoadPicture(imageUrl, subIndex, subLength) {
            let param = {responseType: 'blob'};
            let decodedUrl = decodeURIComponent(imageUrl);
            console.log('下载图片 %s-%s-%s of %s', this.tempPostEdgesIndex, subLength, subIndex, this.tempPostEdgesSize, decodedUrl);
            let imagePath = '';
            await axios.get(decodedUrl, param).then(res => {
                if (res.status === 200 && typeof (res.data) === 'object' && String(res.data) === '[object Blob]') {
                    let imageBlob = res.data;
                    let imageSha = sha1(decodedUrl);
                    let imageName = 'data-' + this.currentId + '-' + imageSha + '.jpg';
                    console.log('下载图片成功! imageSha=%s', imageSha, res);
                    this.$message({message: [`下载图片成功!`, `${this.tempPostEdgesIndex}-${subLength}-${subIndex} of ${this.tempPostEdgesSize}`]});
                    // 图片下载成功, 上传图片
                    let fd = new FormData();
                    fd.append('file', imageBlob, imageName);
                    return {imageName, imageBlob, imageSha, fd};
                }
                console.log('下载图片失败', res);
                throw res;
            }).then(thenObj => {
                if (typeof (thenObj) === 'object') {
                    let {imageName, imageBlob, imageSha, fd} = thenObj;
                    if (typeof (fd) === 'object' && fd instanceof FormData) {
                        return new Promise(((resolve, reject) => {
                            let gmParam = {
                                url: appConfig.host + 'file',
                                method: 'post',
                                data: fd,
                                overrideMimeType: 'multipart/form-data',
                                onload: (resUp) => {
                                    if (resUp.status === 200 && resUp.responseText.includes('upFile : true')) {
                                        let tempPic = {
                                            name: imageName,
                                            data: imageBlob,
                                            index: this.tempPostEdgesIndex,
                                            subIndex,
                                            subLength,
                                        };
                                        this.tempPicList.push(tempPic);
                                        // /data/instagram/{ userId }/{        download imageUrl sha1        }.jpg
                                        // /data/instagram/1433997056/7929ff968af7ac5dc18b9bf9dde0ee0e08c9b6f5.jpg
                                        imagePath = '/data/instagram/' + this.currentId + '/' + imageSha + '.jpg';
                                        console.log('上传图片成功!', tempPic);
                                        let next = {
                                            name: 'doUpdateEdge'
                                        };
                                        this.doPushNext(next);
                                    } else {
                                        console.log('上传图片失败!');
                                        reject(resUp);
                                        return;
                                    }
                                    resolve();
                                },
                                onerror: (eUp) => {
                                    console.log('上传图片时发生错误!', eUp);
                                    reject(eUp);
                                }
                            };
                            GM_xmlhttpRequest(gmParam);
                        }));
                    } else {
                        console.log('reject fd', fd);
                        throw (fd);
                    }
                } else {
                    console.log('reject fd, thenObj:', thenObj);
                    throw (thenObj);
                }
            }).catch(e => {
                throw(e);
            })
            return imagePath;
        },
        async doGetPost() {
            return new Promise((resolve, reject) => {
                let {runTask} = this.sharedState;
                if (!runTask) {
                    let msg = ['获取getPost异常!', 'runTask:' + typeof (runTask)];
                    console.error(...msg);
                    this.$message({message: msg, level: 'error'});
                    reject(msg);
                    return;
                }
                let failMethod = () => {
                    this.tempPost = null;
                    this.tempPostEdges = null;
                    this.tempPostEdgesSize = 0;
                    this.tempPostEdgesIndex = 0;
                };
                let currentId = this.currentId;
                if (currentId >= 0) {
                    let param = {
                        id: currentId
                    };
                    api.gram.getPostNew(param).then(res => {
                        if (res.status === 200 && res.data.status === 'ok') {
                            this.tempPost = res.data;
                            if (!res.data.data.user) {
                                let msg = ['此用户可能已注销!', `current= ${this.current}, cid= ${currentId}, edges= ${this.tempPostEdgesSize}`];
                                console.log(...msg, res);
                                this.$message({message: msg, level: 'error'});
                                // 执行下一个id
                                this.current = -1;
                                resolve();
                                return;
                            }
                            if (!res.data.data.user.edge_owner_to_timeline_media) {
                                let {config = {}} = this.sharedData;
                                let {viewer = {}} = config;
                                let {username = ''} = viewer;
                                let banMsg = 'currentId=' + currentId + ' ' + username + '用户可能被封号!';
                                let msg = ['获取帖子数据异常', banMsg, `res=${JSON.stringify(res.data)}`];
                                this.banMsg = msg;
                                console.log(...msg, res);
                                this.$message({message: msg, level: 'error'});
                                this.$emit('banMsg', msg);
                                api.banMsg = msg;
                                failMethod();
                                reject(res);
                                return;
                            }
                            this.tempPostEdges = res.data.data.user.edge_owner_to_timeline_media.edges;
                            this.tempPostEdgesSize = this.tempPostEdges.length;
                            let msg = ['下载帖子数据成功!', `current= ${this.current}, cid= ${currentId}, edges= ${this.tempPostEdgesSize}`];
                            console.log(...msg, res);
                            this.$message({message: msg});
                            resolve();
                            return;
                        }
                        if (res.status === 429 && res.data.status === 'fail' && res.data['spam']) {
                            let {config = {}} = this.sharedData;
                            let {viewer = {}} = config;
                            let {username = ''} = viewer;
                            let banMsg = username + '用户被封号!';
                            let msg = ['获取帖子失败', banMsg, `任务结束运行,进度=${this.current}`, JSON.stringify(res.data)];
                            this.banMsg = msg;
                            api.banMsg = msg;
                            console.log(...msg);
                            this.$message({message: msg, level: 'error'});
                            this.$emit('banMsg', msg);
                            this.doStop();
                        }
                        failMethod();
                        reject(res);
                    }).catch(e => {
                        failMethod();
                        reject(e);
                    })
                } else {
                    reject('error currentId is ' + currentId)
                }
            })
        },
        async doGetNextId() {
            return new Promise((resolve, reject) => {
                let {runTask} = this.sharedState;
                if (!runTask) {
                    let msg = ['获取nextId异常!', 'runTask:' + typeof (runTask)];
                    console.error(...msg);
                    this.$message({message: msg, level: 'error'});
                    reject(msg);
                    return;
                }
                if (this.current !== -1) {
                    // 当前id正在执行
                    resolve();
                    return;
                }
                api.ins.next().then(res => {
                    if (res.data && res.data.code === 0) {
                        let {current} = res.data.data;
                        let {nextId} = res.data.data;
                        runTask.current = current;
                        runTask.currentId = nextId;
                        let {total = 0, percentSuccess = 0} = runTask;
                        if (total > 0) {
                            percentSuccess = current / total * 100;
                        }
                        runTask.percentSuccess = percentSuccess;
                        this.current = current;
                        this.currentId = nextId;
                        let msg = ['获取用户id成功!', `cur=${current} cid=${nextId}`];
                        console.log(...msg, res);
                        this.$message({message: msg});
                        console.log('清除邮箱计数');
                        localStorage.setItem("emailCount", "0");
                        resolve();
                        return;
                    }
                    this.currentId = '';
                    reject(res);
                }).catch(e => {
                    this.currentId = '';
                    reject(e);
                })
            })
        },
        async doCheckTask() {
            return new Promise((resolve, reject) => {
                if (this.sharedData) {
                    let {config = {}} = this.sharedData;
                    let {viewer} = config;
                    if (viewer) {
                        if (this.isTaskOk) {
                            resolve();
                            return;
                        }
                        let failMethod = () => {
                            this.isTaskOk = false;
                        };
                        let param = {id: '1001283596'};
                        api.gram.getPostNew(param).then(res => {
                            if (res.status === 200 && res.data.status === 'ok') {
                                console.log('检查任务成功!', res);
                                this.isTaskOk = true;
                                resolve();
                                return;
                            }
                            let msg = '检查任务下载失败!';
                            console.error(msg, res);
                            this.$message({message: msg, level: 'error'});
                            failMethod();
                            reject(res);
                        }).catch(e => {
                            failMethod();
                            reject(e);
                        })
                    } else {
                        reject("没有登录信息,未登录")
                    }
                }
            })
        },
        async doGetSharedData() {
            return new Promise(((resolve, reject) => {
                axios.get('/').then(res => {
                    if (res.status === 200) {
                        if(unsafeWindow._sharedData) {
                            this.sharedData = unsafeWindow._sharedData;
                            console.log('获取用户信息 _sharedData:', unsafeWindow._sharedData);
                            resolve();
                            return;
                        }
                        let jsonStr = res.data.between('>window._sharedData =', ';</script>');
                        if (jsonStr) {
                            let obj = JSON.parse(jsonStr);
                            console.log('获取用户信息 _sharedData:', obj);
                            this.sharedData = obj;
                            resolve();
                            return;
                        }
                    }
                    console.error('响应结果错误', res);
                    reject(res);
                }).catch(e => {
                    reject(e);
                })
            }))
        },
        doCheckUser() {
            if (this.sharedData) {
                let {config = {}} = this.sharedData;
                let {viewer} = config;
                if (viewer && viewer.username) {
                    this.username = viewer.username;
                    localStorage.setItem('lastUser', this.username);
                    this.isUserOk = true;
                    return;
                }
                let next = {
                    name: 'doNextUser'
                };
                this.doPushNext(next);
            }
            this.isUserOk = false;
        },
        async doNextUser() {
            return new Promise(((resolve, reject) => {
                api.user.getAll().then(res => {
                    if (res.data && res.data.code === 0) {
                        let lastUser = localStorage.getItem('lastUser');
                        let allUser = res.data.data;
                        let nextUser = '';
                        let i;
                        for (i in allUser) {
                            // @see <a href="https://blog.csdn.net/qq_27093465/article/details/50802104">IntelliJ IDEA中js代码报如下警告的解决方法</a>
                            if (allUser.hasOwnProperty(i)) {
                                let user = allUser[i];
                                if (user.username) {
                                    if (lastUser) {
                                        if (user.username === lastUser) {
                                            i++;
                                            break;
                                        } else {
                                            nextUser = user.username;
                                            break;
                                        }
                                    } else {
                                        nextUser = user.username;
                                        break;
                                    }
                                }
                            }
                        }
                        if (!nextUser) {
                            if (allUser.length > 0) {
                                i = i >= allUser.length ? i - allUser.length : i;
                                for (; i < allUser.length; i++) {
                                    let user = allUser[i];
                                    if (user.username) {
                                        nextUser = user.username;
                                        break;
                                    }
                                }
                            }
                        }
                        if (!nextUser) {
                            console.error('切换下一个用户失败!', lastUser, res);
                            reject(res);
                            return;
                        }
                        localStorage.setItem('nextUser', nextUser);
                        let next = {
                            name: 'doLogin'
                        };
                        this.doPushNext(next);
                        resolve();
                        return;
                    }
                    reject(res);
                }).catch(e => {
                    reject(e);
                })
            }))
        },
        doLogin() {
            return new Promise(((resolve, reject) => {
                let nextUser = localStorage.getItem('nextUser');
                if (!nextUser) {
                    reject('用户名空');
                    return;
                }
                if (window.location.href !== "https://www.instagram.com/") {
                    window.location.href = "https://www.instagram.com/";
                    return;
                }
            }))
        }
    },
    mounted() {
        console.log('document.cookie', document.cookie);
        console.log(this.$options.name + ' mounted', this.runnerId);
        this.doInit();
    },
    unmounted() {
        console.log(this.$options.name + ' unmounted', this.runnerId);
        this.exit = true;
    },
};